using DA.AnimGraph;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;

namespace DA.AnimGraph.Editor {
    internal class AddNodeService : Service {
        public void AddNode(AGANodeModelBase nodeModel, Type bNodeType, Vector2 position) {
            (provider as BlendTreeCanvas).AddNodeData(nodeModel, bNodeType, position);
        }
    }

    internal class BlendTreeCanvas : GraphCanvasBase {
        HandleKeeper<AGAHandle_SubGraph> subGraphHK;
        Dictionary<AUID, HandleKeeper<AGAHandle_Node>> nodeHKs;

        Dictionary<AUID, NodeViewBase> nodes;

        protected override void OnSetHandle(AGAHandleBase handle) {
            Debug.Assert(handle is AGAHandle_SubGraph || handle == null);
            if (handle == null) {
                subGraphHK = default;
                return;
            }
            subGraphHK = new HandleKeeper<AGAHandle_SubGraph>(handle as AGAHandle_SubGraph);
            nodes = new Dictionary<AUID, NodeViewBase>();
        }

        internal BlendTreeCanvas(ContextPaneBase parent) : base(parent) {
        }


        /// <summary>
        /// 返回新增和移除的node，初次调用不返回
        /// </summary>
        (List<AUID> nodeToAdd, List<AUID> nodeToRemove) GetNodeHandles() {
            if (nodeHKs == null) {
                var nodesUuid = subGraphHK.handle.GetAllNodesUuid();
                nodeHKs = new Dictionary<AUID, HandleKeeper<AGAHandle_Node>>(nodesUuid.Length);
                foreach (var uuid in nodesUuid) {
                    nodeHKs.Add(uuid, subGraphHK.handle.GetChildHandle(uuid).ToKeeper<AGAHandle_Node>());
                }
                return (null, null);
            } else {
                var nodesUuid = subGraphHK.handle.GetAllNodesUuid();

                // 处理删除
                var nodeToRemove = new List<AUID>();
                var keys = nodeHKs.Keys.ToArray();
                foreach (AUID uuid in keys) {
                    if (!nodesUuid.Contains(uuid)) {
                        nodeHKs.Remove(uuid);
                        nodeToRemove.Add(uuid);
                    }
                }
                // 处理新增
                var nodeToAdd = new List<AUID>();
                foreach (var uuid in nodesUuid) {
                    if (!nodeHKs.ContainsKey(uuid)) {
                        nodeHKs.Add(uuid, subGraphHK.handle.GetChildHandle(uuid).ToKeeper<AGAHandle_Node>());
                        nodeToAdd.Add(uuid);
                    }
                }
                return (nodeToAdd, nodeToRemove);
            }
        }

        protected override void OnClearUI() {
            base.OnClearUI();
            // ageEnv.OnModeChanged -= OnModeChanged;
            ageContext.serviceManager.RemoveService<AddNodeService>(this);
            // graphView.Q("contentViewContainer").Clear();
        }

        protected override void OnDrawUI() {
            base.OnDrawUI();
            // ageEnv.OnModeChanged += OnModeChanged;
            ageContext.serviceManager.AddService<AddNodeService>(this);
            if (subGraphHK.isDirty) {
                GetNodeHandles();
                subGraphHK.ClearDirty();
            }

            // 创建节点
            var keys = nodeHKs.Keys.ToArray();
            for (int i = 0; i < keys.Length; i++) {
                var nodeHK = nodeHKs[keys[i]];
                if (nodeHK.isDirty) {
                    nodeHK.ClearDirty();
                }
                var vNode = CreateViewNode(nodeHK.handle);
                nodeHKs[keys[i]] = nodeHK;
            }

            // 连线
            ConnectEdges();
        }
        void OnModeChanged() {
            // var newMode = ageEnv.ageMode;
            // switch (newMode) {
            //     case AGEMode.Preview:
            //         graphView.SetEnabled(false);
            //         break;
            //     default:
            //         graphView.SetEnabled(true);
            //         break;
            // }
        }

        protected override void OnUpdateUI() {
            bool edgeDirty = false; // 是否需要更新连线

            List<AUID> nodeToAdd = null;
            List<AUID> nodeToRemove = null;
            if (subGraphHK.isDirty) {
                (nodeToAdd, nodeToRemove) = GetNodeHandles();
                edgeDirty = true;
                subGraphHK.ClearDirty();
            }

            // 新增节点
            if (nodeToAdd != null && nodeToAdd.Count > 0) {
                for (int i = 0; i < nodeToAdd.Count; i++) {
                    var nodeHK = nodeHKs[nodeToAdd[i]];
                    if (nodeHK.isDirty) {
                        nodeHK.ClearDirty();
                    }
                    var vNode = CreateViewNode(nodeHK.handle);
                    nodeHKs[nodeToAdd[i]] = nodeHK;
                }
            }

            // 移除旧节点
            if (nodeToRemove != null && nodeToRemove.Count > 0) {
                foreach (var uuid in nodeToRemove) {
                    RemoveViewNode(uuid);
                }
            }

            // 遍历节点
            foreach (var node in nodes.Values) {
                edgeDirty |= node.OnUpdateUI();
            }

            // 重新连线
            if (edgeDirty) {
                var allEdges = graphView.Query<Edge>().ToList();
                for (int i = 0; i < allEdges.Count; i++) {
                    var e = allEdges[i];
                    e.input?.Disconnect(e);
                    e.output?.Disconnect(e);
                }
                graphView.DeleteElements(allEdges);
                ConnectEdges();
            }
        }

        /// <summary>
        /// 从已有数据生成ViewNode
        /// </summary>
        NodeViewBase CreateViewNode(AGAHandle_Node handle) {
            var viewNodeType = NodeTypeRegister.GetInstance().GetNodeViewTypeByAGANodeType(handle.agaNodeType);
            if (viewNodeType == null) {
                throw new ArgumentNullException($"[AG] cant find NodeView of {handle.agaNodeType}");
            }

            var vNode = Activator.CreateInstance(viewNodeType) as NodeViewBase;
            vNode.Init(handle, graphView, ageEnv);
            graphView.AddElement(vNode);
            nodes.Add(handle.uuid, vNode);
            return vNode;
        }

        /// <summary>
        /// 移除ViewNode
        /// </summary>
        void RemoveViewNode(AUID uuid) {
            var vNode = nodes[uuid];
            graphView.RemoveElement(vNode);
            nodes.Remove(uuid);
        }

        /// <summary>
        /// 全量连线
        /// </summary>
        void ConnectEdges() {
            var edges = subGraphHK.handle.GetAllEdges();
            for (int i = 0; i < edges.Count; i++) {
                var edgeData = edges[i];
                if (nodes.TryGetValue(edgeData.inputNode, out var inputNode)) {
                    if (nodes.TryGetValue(edgeData.outputNode, out var outputNode)) {
                        if (edgeData.outputPort == outputNode.outputPort.uuid) {
                            var inputPorts = inputNode.inputPorts.Find((x) => x.uuid == edgeData.inputPort);
                            if (inputPorts != null) {
                                var edge = new BlendTreeEdge {
                                    output = outputNode.outputPort,
                                    input = inputPorts
                                };
                                graphView.AddElement(edge);
                                edge.input.Connect(edge);
                                edge.output.Connect(edge);
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 提供菜单选项服务
        /// </summary>
        public void AddNodeData(AGANodeModelBase nodeModel, Type bNodeType, Vector2 position) {
            subGraphHK.handle.AddNode(nodeModel, bNodeType, position);
        }

        /// <summary>
        /// 删除节点
        /// </summary>
        /// <param name="nodeToDelete"></param>
        void DeleteNodeData(List<AUID> nodeToDelete) {
            foreach (var node in nodeToDelete) {
                // 也要移除对资源的引用
                var resList = subGraphHK.handle.GetNodeResource(node);
                if (resList != null) {
                    foreach (var res in resList) {
                        ageContext.resourceManager.TryRemoveResource(res);
                    }
                }
                // 移除perk前清理
                subGraphHK.handle.ForeachPerksOnNode(node, p => {
                    p.OnDelete(ageContext);
                });

                subGraphHK.handle.RemoveNode(node);
            }
        }

        /// <summary>
        /// 通过拖动删除edge
        /// 其它删除也调用到这里
        /// </summary>
        public void DeleteEdgesData(List<Edge> edgesToDelete) {
            foreach (var edge in edgesToDelete) {
                D.A(edge is BlendTreeEdge, "出现不正确的edge类型");
                var inputPort = edge.input as BlendTreePort;
                var outputPort = edge.output as BlendTreePort;
                inputPort.Disconnect(edge);
                outputPort.Disconnect(edge);
                var inputNode = inputPort.GetFirstAncestorOfType<NodeViewBase>();
                var outputNode = outputPort.GetFirstAncestorOfType<NodeViewBase>();
                bool isSuccess = subGraphHK.handle.DisconnectNode(inputNode.uuid, inputPort.uuid, outputNode.uuid, outputPort.uuid);
                D.A(isSuccess, "删除edge失败");
            }
        }

        /// <summary>
        /// 通过拖动添加edge
        /// </summary>
        public void AddEdgesData(List<Edge> edgesToCreate) {
            foreach (var edge in edgesToCreate) {
                D.A(edge is BlendTreeEdge, "出现不正确的edge类型");
                var inputPort = edge.input as BlendTreePort;
                var outputPort = edge.output as BlendTreePort;
                var inputNode = inputPort.GetFirstAncestorOfType<NodeViewBase>();
                var outputNode = outputPort.GetFirstAncestorOfType<NodeViewBase>();
                bool isSuccess = subGraphHK.handle.ConnectNode(inputNode.uuid, inputPort.uuid, outputNode.uuid, outputPort.uuid);
                D.A(isSuccess, "添加edge失败");
            }
        }

        /// <summary>
        /// 通过选中删除
        /// </summary>
        protected override void OnDeleteSelection(string operationName, GraphView.AskUser askUser) {
            ageContext.serviceManager.GetService<ShowInspectorService>().ClearInspector();

            switch (operationName) {
                case "Cut":
                case "Delete": {
                    // 删除选中连线
                    var edgesUuidToDelete = graphView.selection.Where((e) => e is BlendTreeEdge).Select(x => x as Edge).ToList();
                    if (edgesUuidToDelete != null && edgesUuidToDelete.Count > 0) {
                        DeleteEdgesData(edgesUuidToDelete);
                    }

                    var nodesToDelete = graphView.selection.Where((e) => e is NodeViewBase).ToList();
                    // 删除本身未选中，但与选中节点连接的连线
                    foreach (var node in nodesToDelete) {
                        var vNode = node as NodeViewBase;
                        var ports = vNode.Query<BlendTreePort>().ToList();
                        foreach (var port in ports) {
                            DeleteEdgesData(port.connections.ToList());
                        }
                    }
                    // 删除选中节点
                    var nodesUuidToDelete = nodesToDelete.Select(x => (x as NodeViewBase).uuid).ToList();
                    if (nodesUuidToDelete != null && nodesUuidToDelete.Count > 0) {
                        DeleteNodeData(nodesUuidToDelete);
                    }
                }
                    break;
            }
            base.OnDeleteSelection(operationName, askUser);
        }

        protected override string OnCopy(IEnumerable<GraphElement> elements) {
            var selection = graphView.selection;

            var nodesUuidToCopy = selection.Where((e) => e is NodeViewBase && e is not NodeView_Result).Select(e => (e as NodeViewBase).uuid).ToList();
            if (nodesUuidToCopy != null) {
                List<AGANode_NodeBase> resultNodes = null;
                List<AGA_Edge> resultEdge = null;

                // 复制节点
                resultNodes = new(nodesUuidToCopy.Count);
                subGraphHK.handle.ForeachNodes((node) => {
                    if (nodesUuidToCopy.Contains(node.uuid)) {
                        // 这里深拷贝然后再添加入数组。要不通过序列化实现？
                        resultNodes.Add(node.data);
                    }
                });

                // 复制连线，挑选出两端的节点都被选中的连线
                var edgeToCopy = selection.Where((e) => e is BlendTreeEdge).Select(e => (e as BlendTreeEdge)).ToList();
                if (edgeToCopy != null) {
                    resultEdge = new(edgeToCopy.Count);
                    for (int i = 0; i < edgeToCopy.Count; i++) {
                        var edge = edgeToCopy[i];
                        var inputPort = edge.input as BlendTreePort;
                        var outputPort = edge.output as BlendTreePort;
                        var inputNode = inputPort.GetFirstAncestorOfType<NodeViewBase>();
                        var outputNode = outputPort.GetFirstAncestorOfType<NodeViewBase>();
                        if (nodesUuidToCopy.Contains(inputNode.uuid) && nodesUuidToCopy.Contains(outputNode.uuid)) {
                            var toAdd = new AGA_Edge(inputNode.uuid, inputPort.uuid, outputNode.uuid, outputPort.uuid);
                            resultEdge.Add(toAdd);
                        }
                    }
                    if (resultEdge.Count == 0) {
                        resultEdge = null;
                    }
                }

                AGEGlobal.GetInstance().clipboard.Copy(ageContext, AGEClipboard.CopyContentFormat.BlendTree, resultNodes, resultEdge);
            }

            return base.OnCopy(elements);
        }

        protected override void OnPaste(string operationName, string data) {
            AGEGlobal.GetInstance().clipboard.Paste(ageContext, out var nodes, out var edges);
            if (nodes != null) {
                PasteNodes(nodes);
            }
            if (edges != null) {
                PasteEdges(edges);
            }
        }

        void PasteNodes(List<AGANode_NodeBase> nodes) {
            foreach (var newNode in nodes) {
                // 处理坐标，临时
                newNode.position += new Vector2(10, 10);
                subGraphHK.handle.PasteNode(newNode);
            }
        }

        void PasteEdges(List<AGA_Edge> edges) {
            foreach (var edge in edges) {
                bool isSuccess = subGraphHK.handle.ConnectNode(edge);
                D.A(isSuccess, "添加edge失败");
            }
        }
    }
}